package com.jcl.cloud.services.crawler.search.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jcl.cloud.common.service.util.HttpClientUtil;
import com.jcl.cloud.common.service.util.PageOperation;
import com.jcl.cloud.services.brain.client.CrawlerBrainClient;
import com.jcl.cloud.services.crawler.search.model.SearchConfigModel;
import com.jcl.cloud.services.crawler.search.service.RedisService;
import com.jcl.cloud.services.crawler.search.util.SerializeUtils;
import com.jcl.cloud.services.crawler.search.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
public class QcwySearchTaskHandler implements SearchTaskHandler {
    private final static Logger logger = LoggerFactory.getLogger(QcwySearchTaskHandler.class);

    @Autowired
    private RedisService redisService;
    @Autowired
    private CrawlerBrainClient crawlerBrainClient;


    @Override
    public void execute(String crawlerId) {

        SearchConfigModel searchConfigModel = null;
        try {
            String searchConfig = this.redisService.hget("unicrawler:task:info:" + crawlerId, "search-config");

            String phase = "";

            if(StringUtils.isBlank(searchConfig)){
                phase = "GRAB_URL";
                searchConfigModel = new SearchConfigModel();
            }else {
                searchConfigModel = JSON.toJavaObject(JSON.parseObject(searchConfig),SearchConfigModel.class);
                phase = searchConfigModel.getPhase();
            }


            if ("GRAB_URL".equalsIgnoreCase(phase)) {
                this.grabUrl(crawlerId,searchConfigModel);
            } else if ("URL_TO_SEARCH".equalsIgnoreCase(phase)) {
                this.urlToSearch(crawlerId, searchConfigModel);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if(searchConfigModel.isAlive()){
                //判断一下队列的长度
                long len =  this.redisService.llen("crawler:brain:search:tasks:" + crawlerId);
                //上传配置
                if(len == 0){//如果url使用完了
                    searchConfigModel.setPhase("GRAB_URL");
                    searchConfigModel.setConfig(null);
                }
                this.redisService.hset("unicrawler:task:info:" + crawlerId, "search-config",JSON.toJSONString(searchConfigModel));


                long currentTime = System.currentTimeMillis();
                long nextExecuteTime = currentTime + 180000 ;
                this.redisService.hset("unicrawler:task:info:"+crawlerId,"nextExecuteTime",String.valueOf(nextExecuteTime));
                //释放任务
                this.redisService.lpush("unicrawler:tasks:all", crawlerId);

            }else {
                //上报cookie失效
                this.crawlerBrainClient.reportCookieFail(crawlerId);
                logger.info("前程无忧   上报cookie失效的爬虫crawlerId = " + crawlerId);
            }
        }

    }


    private void grabUrl(String crawlerId,SearchConfigModel searchConfigModel) {

        String KEY = "";
        boolean isStart = false;
        try {
            String cookieStoreStr = this.redisService.hget("unicrawler:task:info:" + crawlerId, "cookieStore");

            BasicCookieStore cookieStore = SerializeUtils.serializeToObj(cookieStoreStr);
            HttpClientContext context = HttpClientContext.create();
            context.setCookieStore(cookieStore);


            //获取关键词
            String keyWordResult = HttpClientUtil.doGet("http://www.jucailin.com/api/searchresume/keywords?from=qcwy");
            logger.info("获取到的搜索关键词：" + keyWordResult);
            String keyWord = JSON.parseObject(keyWordResult).getString("keywords");
            if (StringUtils.isNotBlank(keyWord) ) {
                isStart = true;
                String pageResult = "";
                //搜索简历
                pageResult = PageOperation.doGet2SearchResumeNew(context);
                logger.info("pageResult===>" + pageResult);


                Thread.sleep((long) (Math.random() * 30 + 5) * 1000);


                Map<String, String> smap = new HashMap();
                KEY = StringUtil.getStrWithRegex(pageResult, "var strKey = \"(.*?)\";");
                smap.put("doType", "SaveEspArea");
                smap.put("KEY", KEY);
                smap.put("esparea", "");
                smap.put("isIndex", "0");
                smap.put("selectarea", "");
                String result1 = PageOperation.doPost2GlobalSearchResumeIndexAjax(smap, context);
                logger.info("result1===>" + result1);


                String __VIEWSTATE = "";
                //String ctrlSerach$search_keyword_txt = "";
                String ctrlSerach$hidSearchValue = keyWord + "#######本科及以上|6#本科及以上|##############近1年|6######0#0#0";
                String hidAccessKey = "";
                String hidCheckUserIds = "";
                String hidCheckKey = "";
                String hidDownloadNum = "";


                String pre__EVENTTARGET = "pagerBottomNew$btnNum";
                for (int i = 1; i <= 5; i++) {
                     Thread.sleep((long) (Math.random() * 30 + 5) * 1000);
                    try {
                        logger.info(String.format("开始获取第%s页的简历数据", i ));
                        Document sdocument = Jsoup.parse(pageResult);
                        __VIEWSTATE = sdocument.getElementById("__VIEWSTATE").attr("value");
                        hidAccessKey = sdocument.getElementById("hidAccessKey").attr("value");
                        hidCheckUserIds = sdocument.getElementById("hidCheckUserIds").attr("value");
                        hidCheckKey = sdocument.getElementById("hidCheckKey").attr("value");
                        hidDownloadNum = sdocument.getElementById("hidDownloadNum").attr("value");


                        String __EVENTTARGET = pre__EVENTTARGET + i;
                        smap = new HashMap();
                        smap.put("__EVENTTARGET", __EVENTTARGET);
                        smap.put("__VIEWSTATE", __VIEWSTATE);
                        smap.put("ctrlSerach$search_keyword_txt", keyWord);
                        smap.put("ctrlSerach$hidSearchValue", ctrlSerach$hidSearchValue);
                        smap.put("hidAccessKey", hidAccessKey);
                        smap.put("hidCheckUserIds", hidCheckUserIds);
                        smap.put("hidCheckKey", hidCheckKey);
                        smap.put("hidDownloadNum", hidDownloadNum);
                        smap.put("hidSearchTimestamp", String.valueOf(new Date().getTime()));

                        pageResult = PageOperation.doPost2SearchResumeNew(smap, context);
                        logger.info("pageResult===>" + pageResult);
                        Thread.sleep((long) (Math.random() * 20 + 5) * 1000);

                        List<String> urlList = StringUtil.getResumeViewUrlList(pageResult);


                        //上传url
                        for (String url:urlList){
                            this.redisService.lpush("crawler:brain:search:tasks:" + crawlerId,url);
                            Thread.sleep(300);
                        }



                        Thread.sleep((long) (Math.random() * 15) * 1000);
                    } catch (Exception e) {
                        logger.error(String.format("前程无忧网站翻页获取简历url发生异常：%s ", e.getMessage()), e);
                    }
                }
            } else {
                Thread.sleep((long) (Math.random() * 5) * 1000);
            }
        } catch (Exception e) {
            logger.error(String.format("前程无忧网站通过关键词获取url发生异常：%s ", e.getMessage()), e);
        }finally {

            Map map = new HashMap();
            map.put("KEY",KEY);
            searchConfigModel.setPhase("URL_TO_SEARCH");
            searchConfigModel.setConfig(map);

            if (StringUtils.isBlank(KEY) && isStart) {
                searchConfigModel.setAlive(false);
                logger.info("GRAB_URL  发生异常，KEY值为空");
            }else {
                searchConfigModel.setAlive(true);
            }
        }
    }


    private void urlToSearch(String crawlerId, SearchConfigModel searchConfigModel) {

        int crawlFailTimes = 0;
        int needDeLockTimes = 0;
        try {
            String accountKey = this.redisService.hget("unicrawler:task:info:" + crawlerId, "accountKey");
            String cookieStoreStr = this.redisService.hget("unicrawler:task:info:" + crawlerId, "cookieStore");

            BasicCookieStore cookieStore = SerializeUtils.serializeToObj(cookieStoreStr);
            HttpClientContext context = HttpClientContext.create();
            context.setCookieStore(cookieStore);


            for (int n = 0;n<=25;n++) {



                try {
                    String url =  this.redisService.rpop("crawler:brain:search:tasks:" + crawlerId);

                    if (StringUtils.isNotBlank(url)) {
                        logger.info("前程无忧网站爬取简历详细信息连续失败的次数crawlFailTimes = " + (crawlFailTimes++) );

                        Thread.sleep((long) (Math.random() * 20) * 1000);

                        String Key = (String) searchConfigModel.getConfig().get("KEY");
                        Map smap = new HashMap();
                        smap.put("logType", "event");
                        smap.put("pageNo", "3");
                        smap.put("memo", "");
                        smap.put("eventNo", "8");
                        smap.put("Key", Key);
                        smap.put("rnd", String.valueOf(Math.random()));
                        smap.put("Referer", "https://ehire.51job.com/Candidate/SearchResumeNew.aspx");

                        String result2 = PageOperation.doGlobalActionLogAjax(smap, context);
                        logger.info("result2===>" + result2);


                        Thread.sleep((long) (Math.random() * 10) * 1000);


                        String result3 = PageOperation.doGet2ResumeView(url, context);





                        //解析上传
                        Map<String, String> argsMap = new HashMap<>();
                        Document document = Jsoup.parse(result3, "UTF-8");


                        //判断是否需要验证码解锁
                        boolean isNeedDeLock = this.needDeLock(document);
                        if(isNeedDeLock){
                            logger.info("前程无忧发现需要解锁的次数needDeLockTimes：" + needDeLockTimes);
                            needDeLockTimes++;
                            if(needDeLockTimes > 5){
                                //上报需要进行解锁
                                this.redisService.hset("unicrawler:task:info:"+crawlerId,"isNeedDeLock","true");
                                //上报cookie失效
                                crawlFailTimes = 8;
                                break;
                            }
                        }else {
                            needDeLockTimes = 0;
                        }



                        String realname = document.select("td:containsOwn(ID:)").text();
                        logger.info("前程无忧   realname = " + realname);
                        argsMap.put("realname", realname);

                        String baseInfo = document.select("td:containsOwn(现居住)").text();

                        logger.info("前程无忧   baseInfo = " + baseInfo);
                        String sex = baseInfo.split("|")[0];
                        logger.info("前程无忧   sex = " + sex);
                        argsMap.put("sex", sex);


                        String mobile = "";
                        argsMap.put("mobile", mobile);

                        String email = "";
                        argsMap.put("email", email);


                        try {
                            String birthday = baseInfo.split("\\|")[1];
                            argsMap.put("birthday", birthday);
                        } catch (Exception e) {
                           logger.error("前程无忧  解析birthday发生异常：" + e.getMessage(),e);
                        }


                        String update_date = document.select("span:containsOwn(更新时间) > b").text();
                        argsMap.put("update_date", update_date);
                        logger.info("前程无忧   update_date = " + update_date);


                        if(StringUtils.isNotBlank(realname) || StringUtils.isNotBlank(sex) || StringUtils.isNotBlank(update_date)){
                            crawlFailTimes = 0;
                        }


                        String work_detail = null;
                        String edu_detail = null;
                        String project_detail = null;
                        try {
                            String current_salary = document.select("td:containsOwn(目前年收入) > span:eq(0)").text();
                            argsMap.put("current_salary", current_salary);


                            String DesiredSalaryScope = document.select("td:containsOwn(期望薪资) + td").text();
                            Map<String, String> salaryMap = null;
                            String desire_salary_start = "";
                            argsMap.put("desire_salary_start", desire_salary_start);
                            String desire_salary_end = "";
                            argsMap.put("desire_salary_end", desire_salary_end);


                            String evaluate = document.select("td:containsOwn(自我评价) + td").html();
                            argsMap.put("evaluate", evaluate);

                            String arrival_info = document.select("td:containsOwn(到岗时间) + td").text();
                            argsMap.put("arrival_info", arrival_info);


                            String native_place = document.select("td:containsOwn(户口/国籍) + td").text();
                            argsMap.put("native_place", native_place);


                            String workyear = baseInfo.split("\\|")[3];
                            argsMap.put("workyear", StringUtil.getNumFromStr(workyear));


                            String work_last_company = document.select("td:containsOwn(公　司：) + td").text();
                            argsMap.put("work_last_company", work_last_company);


                            String work_last_position = document.select("td:containsOwn(职　位：) + td").text();
                            argsMap.put("work_last_position", work_last_position);


                            String edu_last_education = document.select("td:containsOwn(学历/学位：) + td").text();
                            argsMap.put("edu_last_education", edu_last_education);


                            String edu_last_school = document.select("td:containsOwn(学　校：) + td").text();
                            argsMap.put("edu_last_school", edu_last_school);

                            String edu_last_major = document.select("td:containsOwn(专　业：) + td").text();
                            argsMap.put("edu_last_major", edu_last_major);

                            String source_sub = "51job";
                            argsMap.put("source_sub", source_sub);

                            String current_city = baseInfo.split("\\|")[2];
                            argsMap.put("current_city", current_city.replaceAll("现居住", ""));

                            String current_address = baseInfo.split("\\|")[2];
                            argsMap.put("current_address", current_address.replaceAll("现居住", ""));


                            work_detail = document.select("tr:contains(工作经验) + tr>td>table  table:has(td.time)").outerHtml();
                            argsMap.put("work_detail", work_detail);

                            edu_detail = document.select("tr:contains(教育经历) + tr>td>table  table:has(td.time)").outerHtml();
                            argsMap.put("edu_detail", edu_detail);

                            project_detail = document.select("tr:contains(项目经验) + tr>td>table  table:has(td.time)").outerHtml();
                            argsMap.put("project_detail", project_detail);


                            Map buyResumeContextMap = new HashMap();
                            buyResumeContextMap.put("ResumeViewUrl",url);
                            buyResumeContextMap.put("accountKey",accountKey);


                            argsMap.put("external_msg",JSON.toJSONString(buyResumeContextMap));


                            logger.info("前程无忧搜索简历  external_msg = " + JSON.toJSONString(buyResumeContextMap));


                        } catch (Exception e) {
                            logger.error(String.format("前程无忧  解析相关字段发生异常：%s",e.getMessage()),e);
                        }


                        //crawlFailTimes = 0;



                        //上传
                        logger.info("上传的信息如下：" + JSON.toJSONString(argsMap));  //http://www.jucailin.com/api/searchresume/save
                        String result = HttpClientUtil.doPostJson("http://www.jucailin.com/api/searchresume/save",JSON.toJSONString(argsMap));
                        logger.info("前程无忧上传简历信息的返回结果为：" + result);

                        String code = JSON.parseObject(result).getString("code");
                        if ("200".equals(code)) {
                            logger.info("上传数据成功");

                            String resume_id = String.valueOf(JSONObject.parseObject(result).getJSONObject("data").getInteger("id"));
                            logger.info("前程无忧的resume_id = " + resume_id);

                            //上传工作经历
                            List<Map<String, String>> worksList = StringUtil.htmlWD2MapQcwy(work_detail);
                            for (int i = 0; i < worksList.size(); i++) {
                                Map workMap = worksList.get(i);
                                workMap.put("resume_id", resume_id);
                                HttpClientUtil.doPostJson("http://www.jucailin.com/api/searchresume/worksave", JSON.toJSONString(workMap));
                            }

                            //上传教育经历
                            List<Map<String, String>> edusList = StringUtil.htmlED2MapQcwy(edu_detail);
                            for (int i = 0; i < edusList.size(); i++) {
                                Map eduMap = edusList.get(i);
                                eduMap.put("resume_id", resume_id);
                                HttpClientUtil.doPostJson("http://www.jucailin.com/api/searchresume/edusave", JSON.toJSONString(eduMap));
                            }


                            //上传项目经历
                            List<Map<String, String>> projectsList = StringUtil.htmlPD2MapQcwy(project_detail);
                            for (int i = 0; i < projectsList.size(); i++) {
                                Map projectMap = projectsList.get(i);
                                projectMap.put("resume_id", resume_id);
                                HttpClientUtil.doPostJson("http://www.jucailin.com/api/searchresume/projectsave", JSON.toJSONString(projectMap));
                            }
                        }

                        Thread.sleep((long) (Math.random() * 10) * 1000);
                    }else {
                        logger.info("前程无忧  无爬取详细信息的url");

                    }
                }catch (NullPointerException e){
                    crawlFailTimes = 0;
                } catch (ArrayIndexOutOfBoundsException e){
                    crawlFailTimes = 0;
                } catch (Exception e) {
                    if(crawlFailTimes >= 6){
                        break;
                    }
                    logger.error(String.format("前程无忧网站获取单个简历信息发生异常：%s ", e.getMessage()), e);
                }
            }

            Thread.sleep((long) (Math.random() * 10) * 1000);
        } catch (Exception e) {
            logger.error(String.format("前程无忧网站通过url获取简历信息发生异常：%s ", e.getMessage()), e);
        }finally {

           /* //判断一下队列的长度
            long len =  this.redisService.llen("crawler:brain:search:tasks:" + crawlerId);
            //上传配置
            if(len == 0){//如果url使用完了
               searchConfigModel.setPhase("GRAB_URL");
               searchConfigModel.setConfig(null);
            }
            this.redisService.hset("unicrawler:task:info:" + crawlerId, "search-config",JSON.toJSONString(searchConfigModel));*/

            if(crawlFailTimes >= 6){
                searchConfigModel.setAlive(false);
            }else {
                searchConfigModel.setAlive(true);
            }

        }
    }




    private boolean  needDeLock(Document document){

        boolean flag = false;

        try {
            Elements elements =  document.getElementsByTag("title");


            if(elements.size() != 0){

                String titleStr = elements.get(0).text();
                String __VIEWSTATEValue = document.getElementById("__VIEWSTATE").attr("value");

                logger.info("titleStr = " + titleStr);
                logger.info("__VIEWSTATEValue = " + __VIEWSTATEValue);
                logger.info(String.format("__VIEWSTATEValue的字符串长度：%d",__VIEWSTATEValue.length()));

                if(titleStr.contains("简历ID") && StringUtils.isNotBlank(__VIEWSTATEValue)&&__VIEWSTATEValue.length() > 600){
                    logger.info("调用接口返回的简历详细信息正常");
                }else if(!titleStr.contains("简历ID") &&  StringUtils.isBlank(titleStr) &&__VIEWSTATEValue.length() < 600 ){//&& StringUtils.isBlank(__VIEWSTATEValue)
                    flag = true;
                    logger.info("调用接口返回的简历详细信息异常，需要解封");
                }else if(titleStr.contains("人才招聘-前程无忧")&&__VIEWSTATEValue.length() < 600){
                    flag = true;
                    logger.info("接口返回:人才招聘-前程无忧     调用接口返回的简历详细信息异常，需要解封");
                }else {
                    flag = true;
                }

            }

          /*  String style = document.getElementById("divVerifyCode_ch").attr("style");

            logger.info("divVerifyCode_ch的style = " + style);
            if(StringUtils.isNotBlank(style) && !style.contains("display:none;")){
                flag = true;
            }*/
        } catch (Exception e) {
            logger.error("判断是否需要解锁发生异常：" + e.getMessage(),e);
        }

        return flag;
    }

}
